package cn.edu.tju.elm.service;

import cn.edu.tju.elm.model.VirtualWallet;
import cn.edu.tju.elm.model.WalletTransaction;
import cn.edu.tju.elm.model.RewardRule;
import cn.edu.tju.elm.model.CreditRating;
import cn.edu.tju.elm.model.TransactionType;
import cn.edu.tju.elm.repository.VirtualWalletRepository;
import cn.edu.tju.elm.repository.WalletTransactionRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;

@Service
@Transactional
public class VirtualWalletServiceImpl implements VirtualWalletService {

    private static final Logger logger = LoggerFactory.getLogger(VirtualWalletServiceImpl.class);

    @Autowired
    private VirtualWalletRepository walletRepository;

    @Autowired
    private WalletTransactionRepository transactionRepository;

    @Autowired
    private RewardRuleService rewardRuleService;

    @Autowired
    private CreditService creditService;

    @Autowired
    private UserAuthorityService userAuthorityService;

    @Override
    @Transactional
    public VirtualWallet createWallet(Long userId) {
        logger.info("开始为用户 {} 创建钱包", userId);
        
        try {
            userAuthorityService.getUserById(userId);
        } catch (IllegalArgumentException e) {
            logger.error("用户 {} 不存在，无法创建钱包", userId);
            throw new IllegalArgumentException("用户不存在: " + userId);
        }
        
        boolean walletExists = walletRepository.existsByUserId(userId);
        logger.info("用户 {} 钱包存在检查结果: {}", userId, walletExists);
        
        if (walletExists) {
            logger.warn("用户 {} 已拥有钱包，创建失败", userId);
            throw new IllegalArgumentException("用户已拥有钱包");
        }

        try {
            VirtualWallet wallet = new VirtualWallet();
            wallet.setUserId(userId);
            wallet.setBalance(BigDecimal.ZERO);
            wallet.setFrozenAmount(BigDecimal.ZERO);
            wallet.setUsedCredit(BigDecimal.ZERO);
            // 普通用户初始信用额度为0
            wallet.setCreditLimit(BigDecimal.ZERO);
            wallet.setCreditRating(CreditRating.REGULAR);
            wallet.setIsActive(true);
            wallet.setCreateTime(LocalDateTime.now());
            wallet.setUpdateTime(LocalDateTime.now());

            VirtualWallet savedWallet = walletRepository.save(wallet);
            logger.info("为用户 {} 创建钱包成功，钱包ID: {}, 初始信用额度: 0元", userId, savedWallet.getId());
            
            return savedWallet;
        } catch (Exception e) {
            logger.error("为用户 {} 创建钱包时发生异常: {}", userId, e.getMessage(), e);
            throw new RuntimeException("创建钱包失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public WalletTransaction recharge(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.RECHARGE, userId);
        logger.info("用户 {} 开始充值，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        RewardRule rewardRule = getApplicableRewardRule(userId, amount);
        logger.info("用户 {} 充值使用的奖励规则: {}, 用户类型: {}", 
                   userId, rewardRule.getRuleName(), 
                   userAuthorityService.isMerchant(userId) ? "商家" : "普通用户");
        
        WalletTransaction transaction = wallet.recharge(amount, rewardRule, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        // 检查是否满足VIP激活条件（单次充值金额满1000元）
        if (amount.compareTo(new BigDecimal("1000.00")) >= 0) {
            try {
                // 检查用户是否已经是VIP
                if (!creditService.isVipUser(userId)) {
                    // 单次充值满1000元，自动激活VIP，默认有效期1年
                    LocalDateTime expireTime = LocalDateTime.now().plusYears(1);
                    // 这里会通过setVipStatus自动设置2000元信用额度
                    creditService.setVipStatus(userId, true, expireTime);
                    
                    logger.info("用户 {} 单次充值满1000元，自动激活VIP并获得2000元信用额度，有效期至: {}", userId, expireTime);
                } else {
                    logger.info("用户 {} 已经是VIP用户，无需重复激活", userId);
                }
            } catch (Exception e) {
                logger.error("用户 {} VIP激活失败: {}", userId, e.getMessage(), e);
                // VIP激活失败不影响充值操作
            }
        }
        
        logger.info("用户 {} 充值成功，交易ID: {}, 参考ID: {}", userId, savedTransaction.getId(), referenceId);
        return savedTransaction;
    }

    @Override
    @Transactional
    public WalletTransaction withdraw(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.WITHDRAW, userId);
        logger.info("用户 {} 开始提现，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        RewardRule rewardRule = getApplicableRewardRule(userId, amount);
        BigDecimal fee = rewardRule.calculateWithdrawFee(amount);
        logger.info("用户 {} 提现使用的奖励规则: {}, 手续费率: {}, 手续费: {}, 用户类型: {}", 
                   userId, rewardRule.getRuleName(), rewardRule.getWithdrawFeeRate(), fee,
                   userAuthorityService.isMerchant(userId) ? "商家" : "普通用户");
        
        WalletTransaction transaction = wallet.withdraw(amount, rewardRule, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        logger.info("用户 {} 提现成功，交易ID: {}, 参考ID: {}, 实际扣除金额: {}", 
                   userId, savedTransaction.getId(), referenceId, amount.add(fee));
        return savedTransaction;
    }

    @Override
    @Transactional
    public WalletTransaction pay(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.PAYMENT, userId);
        logger.info("用户 {} 开始支付，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        WalletTransaction transaction = wallet.debit(amount, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        logger.info("用户 {} 支付成功，交易ID: {}, 参考ID: {}", userId, savedTransaction.getId(), referenceId);
        return savedTransaction;
    }

    @Override
    @Transactional
    public WalletTransaction freeze(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.FREEZE, userId);
        logger.info("用户 {} 开始冻结资金，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        WalletTransaction transaction = wallet.freeze(amount, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        logger.info("用户 {} 资金冻结成功，交易ID: {}, 参考ID: {}", userId, savedTransaction.getId(), referenceId);
        return savedTransaction;
    }

    @Override
    @Transactional
    public WalletTransaction unfreeze(Long userId, Long transactionId) {
        logger.info("用户 {} 开始确认收货解冻资金，交易ID: {}", userId, transactionId);
        
        // 1. 根据交易ID查找对应的转账交易记录
        WalletTransaction transferTransaction = transactionRepository.findById(transactionId)
                .orElseThrow(() -> {
                    logger.error("交易ID {} 对应的交易记录不存在", transactionId);
                    return new IllegalArgumentException("交易记录不存在");
                });
        
        // 2. 验证交易类型是否为转入冻结（TRANSFER_IN）
        if (transferTransaction.getTransactionType() != TransactionType.TRANSFER_IN) {
            logger.error("交易ID {} 的类型不是转入冻结，无法解冻。交易类型: {}", 
                        transactionId, transferTransaction.getTransactionType());
            throw new IllegalArgumentException("只能解冻转入冻结类型的交易");
        }
        
        // 3. 验证用户权限：只有付款方才能确认收货
        if (!isPaymentUser(transferTransaction, userId)) {
            logger.error("用户 {} 无权确认交易 {} 的收货", userId, transactionId);
            throw new IllegalArgumentException("无权确认此交易的收货");
        }
        
        // 4. 获取商家的钱包（收款方）
        Long merchantWalletId = transferTransaction.getWalletId();
        VirtualWallet merchantWallet = getWalletById(merchantWalletId);
        
        // 5. 验证资金是否处于冻结状态
        if (merchantWallet.getFrozenAmount().compareTo(transferTransaction.getAmount()) < 0) {
            logger.error("商家钱包冻结资金不足，无法解冻。冻结金额: {}, 需要解冻金额: {}", 
                        merchantWallet.getFrozenAmount(), transferTransaction.getAmount());
            throw new IllegalStateException("冻结资金不足，无法解冻");
        }
        
        // 6. 执行解冻操作
        String referenceId = generateReferenceId(TransactionType.UNFREEZE, userId);
        WalletTransaction unfreezeTransaction = merchantWallet.unfreeze(transferTransaction.getAmount(), referenceId);
        unfreezeTransaction.setDescription(String.format("确认收货解冻 - 交易ID: %s - 客户: %s", transactionId, userId));
        
        // 7. 保存更新
        walletRepository.save(merchantWallet);
        WalletTransaction savedTransaction = transactionRepository.save(unfreezeTransaction);
        
        logger.info("用户 {} 确认收货成功，交易 {} 资金解冻完成，解冻交易ID: {}", userId, transactionId, savedTransaction.getId());
        return savedTransaction;
    }

    @Override
    @Transactional
    public List<WalletTransaction> transfer(Long fromUserId, Long toUserId, BigDecimal amount, String description) {
        try {
            if (fromUserId.equals(toUserId)) {
                logger.error("转账失败：不能向自己转账，用户ID: {}", fromUserId);
                throw new IllegalArgumentException("不能向自己转账");
            }
            
            String orderId = description != null && description.startsWith("ORDER_") ? 
                           description : generateReferenceId(TransactionType.TRANSFER_OUT, fromUserId);
            
            logger.info("开始转账: 从用户 {} 到用户 {}, 金额: {}, 订单ID: {}", fromUserId, toUserId, amount, orderId);
            
            VirtualWallet fromWallet = getWalletByUserIdWithLock(fromUserId);
            VirtualWallet toWallet = getWalletByUserIdWithLock(toUserId);
            
            logger.info("转账前 - 付款方用户{}: 余额={}, 可用余额={}, 冻结金额={}", 
                        fromUserId, fromWallet.getBalance(), fromWallet.getAvailableBalance(), fromWallet.getFrozenAmount());
            logger.info("转账前 - 收款方用户{}: 余额={}, 可用余额={}, 冻结金额={}", 
                        toUserId, toWallet.getBalance(), toWallet.getAvailableBalance(), toWallet.getFrozenAmount());
            
            WalletTransaction fromTransaction = fromWallet.transferOut(amount, toUserId.toString(), orderId);
            if (description != null) {
                fromTransaction.setDescription(description);
            }
            
            WalletTransaction toTransaction = toWallet.transferInAndFreeze(amount, fromUserId.toString(), orderId);
            
            walletRepository.save(fromWallet);
            walletRepository.save(toWallet);
            
            WalletTransaction savedFromTransaction = transactionRepository.save(fromTransaction);
            WalletTransaction savedToTransaction = transactionRepository.save(toTransaction);
            
            savedFromTransaction.setRelatedTransactionId(savedToTransaction.getId());
            savedToTransaction.setRelatedTransactionId(savedFromTransaction.getId());
            
            transactionRepository.save(savedFromTransaction);
            transactionRepository.save(savedToTransaction);
            
            logger.info("转账后 - 付款方用户{}: 余额={}, 可用余额={}, 冻结金额={}", 
                        fromUserId, fromWallet.getBalance(), fromWallet.getAvailableBalance(), fromWallet.getFrozenAmount());
            logger.info("转账后 - 收款方用户{}: 余额={}, 可用余额={}, 冻结金额={}", 
                        toUserId, toWallet.getBalance(), toWallet.getAvailableBalance(), toWallet.getFrozenAmount());
            
            logger.info("转账成功: 从用户 {} 到用户 {}, 金额: {}, 订单ID: {}, 交易ID: {} 和 {}", 
                        fromUserId, toUserId, amount, orderId, savedFromTransaction.getId(), savedToTransaction.getId());
            
            return List.of(savedFromTransaction, savedToTransaction);
        } catch (VirtualWallet.InsufficientBalanceException e) {
            logger.error("转账失败 - 余额不足: 从用户 {} 到用户 {}, 金额: {}, 错误: {}", 
                        fromUserId, toUserId, amount, e.getMessage());
            throw e;
        } catch (IllegalArgumentException e) {
            logger.error("转账失败 - 参数错误: 从用户 {} 到用户 {}, 金额: {}, 错误: {}", 
                        fromUserId, toUserId, amount, e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error("转账失败 - 系统异常: 从用户 {} 到用户 {}, 金额: {}, 错误: {}", 
                        fromUserId, toUserId, amount, e.getMessage(), e);
            throw new RuntimeException("转账失败: " + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public WalletTransaction payWithCredit(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.CREDIT_PAYMENT, userId);
        logger.info("用户 {} 开始信用支付，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        WalletTransaction transaction = wallet.payWithCredit(amount, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        logger.info("用户 {} 信用支付成功，交易ID: {}, 参考ID: {}", userId, savedTransaction.getId(), referenceId);
        return savedTransaction;
    }

    @Override
    @Transactional
    public WalletTransaction repayCredit(Long userId, BigDecimal amount) {
        String referenceId = generateReferenceId(TransactionType.CREDIT_REPAYMENT, userId);
        logger.info("用户 {} 开始信用还款，金额: {}, 自动生成参考ID: {}", userId, amount, referenceId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        
        WalletTransaction transaction = wallet.repayCredit(amount, referenceId);
        
        walletRepository.save(wallet);
        WalletTransaction savedTransaction = transactionRepository.save(transaction);
        
        logger.info("用户 {} 信用还款成功，交易ID: {}, 参考ID: {}", userId, savedTransaction.getId(), referenceId);
        return savedTransaction;
    }

    @Override
    @Transactional
    public void setCreditLimit(Long userId, BigDecimal creditLimit) {
        logger.info("为用户 {} 设置信用额度: {}", userId, creditLimit);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        wallet.setCreditLimit(creditLimit);
        wallet.setUpdateTime(LocalDateTime.now());
        walletRepository.save(wallet);
        
        logger.info("用户 {} 信用额度设置成功", userId);
    }

    @Override
    @Transactional
    public void setVipStatus(Long userId, boolean isVip, LocalDateTime expireTime) {
        logger.info("为用户 {} 设置VIP状态: {}, 过期时间: {}", userId, isVip, expireTime);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        wallet.setVipStatus(isVip, expireTime);
        wallet.setUpdateTime(LocalDateTime.now());
        walletRepository.save(wallet);
        
        logger.info("用户 {} VIP状态设置成功", userId);
    }

    @Override
    public BigDecimal getBalance(Long userId) {
        logger.debug("查询用户 {} 的余额", userId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal balance = wallet.getBalance();
        
        logger.debug("用户 {} 的余额: {}", userId, balance);
        return balance;
    }

    @Override
    public BigDecimal getAvailableBalance(Long userId) {
        logger.debug("查询用户 {} 的可用余额", userId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        BigDecimal availableBalance = wallet.getAvailableBalance();
        
        logger.debug("用户 {} 的可用余额: {}", userId, availableBalance);
        return availableBalance;
    }

    @Override
    public VirtualWallet getWalletByUserId(Long userId) {
        logger.debug("查询用户 {} 的钱包信息", userId);
        
        Optional<VirtualWallet> walletOpt = walletRepository.findByUserId(userId);
        if (walletOpt.isEmpty()) {
            logger.warn("用户 {} 的钱包不存在", userId);
            throw new IllegalArgumentException("用户 " + userId + " 的钱包不存在");
        }
        
        VirtualWallet wallet = walletOpt.get();
        logger.debug("用户 {} 的钱包查询成功，钱包ID: {}", userId, wallet.getId());
        return wallet;
    }

    @Override
    public List<WalletTransaction> getTransactionHistory(Long userId) {
        logger.debug("查询用户 {} 的交易历史", userId);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        List<WalletTransaction> transactions = transactionRepository.findByWalletIdOrderByCreateTimeDesc(wallet.getId());
        
        logger.debug("用户 {} 的交易历史记录数: {}", userId, transactions.size());
        return transactions;
    }

    @Override
    public List<WalletTransaction> getTransactionHistoryByTimeRange(Long userId, 
                                                                   LocalDateTime startTime, 
                                                                   LocalDateTime endTime) {
        logger.debug("查询用户 {} 在 {} 到 {} 期间的交易历史", userId, startTime, endTime);
        
        VirtualWallet wallet = getWalletByUserId(userId);
        List<WalletTransaction> transactions = transactionRepository.findByWalletIdAndCreateTimeBetweenOrderByCreateTimeDesc(
            wallet.getId(), startTime, endTime);
        
        logger.debug("用户 {} 在指定时间范围内的交易记录数: {}", userId, transactions.size());
        return transactions;
    }

    @Override
    public RewardRule getCurrentRewardRule() {
        return rewardRuleService.getDefaultUserRewardRule();
    }

    private VirtualWallet getWalletByUserIdWithLock(Long userId) {
        Optional<VirtualWallet> walletOpt = walletRepository.findByUserIdWithLock(userId);
        if (walletOpt.isEmpty()) {
            logger.error("带锁查询失败：用户 {} 的钱包不存在", userId);
            throw new IllegalArgumentException("用户 " + userId + " 的钱包不存在");
        }
        VirtualWallet wallet = walletOpt.get();
        logger.debug("带锁查询成功：用户 {} 的钱包ID: {}", userId, wallet.getId());
        return wallet;
    }

    private VirtualWallet getWalletById(Long walletId) {
        Optional<VirtualWallet> walletOpt = walletRepository.findById(walletId);
        if (walletOpt.isEmpty()) {
            logger.error("钱包不存在，钱包ID: {}", walletId);
            throw new IllegalArgumentException("钱包不存在: " + walletId);
        }
        return walletOpt.get();
    }

    private boolean isPaymentUser(WalletTransaction transaction, Long userId) {
        // 通过关联交易记录来验证用户是否为付款方
        if (transaction.getRelatedTransactionId() != null) {
            Optional<WalletTransaction> relatedTransactionOpt = 
                transactionRepository.findById(transaction.getRelatedTransactionId());
            if (relatedTransactionOpt.isPresent()) {
                WalletTransaction relatedTransaction = relatedTransactionOpt.get();
                // 付款方的交易类型是 TRANSFER_OUT
                if (relatedTransaction.getTransactionType() == TransactionType.TRANSFER_OUT) {
                    // 获取付款方钱包并验证用户ID
                    VirtualWallet payerWallet = getWalletById(relatedTransaction.getWalletId());
                    boolean isPayer = payerWallet.getUserId().equals(userId);
                    logger.debug("验证付款方权限: 用户ID={}, 钱包用户ID={}, 结果={}", 
                                userId, payerWallet.getUserId(), isPayer);
                    return isPayer;
                }
            }
        }
        
        // 备用验证：检查交易描述
        if (transaction.getDescription() != null && 
            transaction.getDescription().contains("客户: " + userId)) {
            logger.debug("通过交易描述验证付款方权限成功: 用户ID={}", userId);
            return true;
        }
        
        logger.warn("无法验证用户 {} 是否为交易 {} 的付款方", userId, transaction.getId());
        return false;
    }

    private String generateReferenceId(TransactionType transactionType, Long userId) {
        String prefix = getPrefixByType(transactionType);
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        String random = String.format("%04d", ThreadLocalRandom.current().nextInt(10000));
        
        String referenceId = String.format("%s_%d_%s_%s", prefix, userId, timestamp, random);
        logger.debug("生成参考ID: {}", referenceId);
        return referenceId;
    }
    
    private String getPrefixByType(TransactionType type) {
        switch (type) {
            case RECHARGE: return "RECH";
            case WITHDRAW: return "WITH";
            case PAYMENT: return "PAY";
            case TRANSFER_OUT: return "ORDER";
            case TRANSFER_IN: return "ORDER";
            case FREEZE: return "FRZ";
            case UNFREEZE: return "UNFRZ";
            case CREDIT_PAYMENT: return "CRDPAY";
            case CREDIT_REPAYMENT: return "CRDREPAY";
            case REFUND: return "REF";
            case REWARD: return "REW";
            case FEE: return "FEE";
            default: return "TXN";
        }
    }

    private RewardRule getApplicableRewardRule(Long userId, BigDecimal amount) {
        logger.debug("获取用户 {} 适用于金额 {} 的奖励规则", userId, amount);
        
        RewardRule rule = rewardRuleService.getRewardRuleByUserId(userId);
        
        if (!userAuthorityService.isMerchant(userId) && 
            rule.getMinRechargeAmount() != null && 
            rule.getMinRechargeAmount().compareTo(amount) > 0) {
            logger.debug("用户 {} 金额 {} 不满足规则门槛 {}，使用无奖励版本", 
                        userId, amount, rule.getMinRechargeAmount());
            RewardRule noRewardRule = new RewardRule();
            noRewardRule.setRuleName(rule.getRuleName() + " (无奖励)");
            noRewardRule.setAuthorityName(rule.getAuthorityName()); 
            noRewardRule.setRewardAmount(BigDecimal.ZERO);
            noRewardRule.setRewardRate(BigDecimal.ZERO);
            noRewardRule.setWithdrawFeeRate(rule.getWithdrawFeeRate());
            noRewardRule.setIsActive(true);
            return noRewardRule;
        }
        
        logger.debug("用户 {} 金额 {} 满足规则门槛，使用完整奖励规则", userId, amount);
        return rule;
    }
}